Public Class AccountCleaner
    Implements ICleaner

    Private Const _itemName As String = "accounts"

#Region "Shared Interface"

    Private Shared _accountCleaner As AccountCleaner

    Public Shared Function GetInstance() As AccountCleaner
        Try
            If _accountCleaner Is Nothing Then
                _accountCleaner = New AccountCleaner
            End If
        Finally
        End Try

        Return _accountCleaner

    End Function

#End Region

    'singleton pattern - cannot be constructed directly
    Private Sub New()

    End Sub

    Public ReadOnly Property ItemName() As String Implements ICleaner.ItemName
        Get
            Return _itemName
        End Get
    End Property

    Public ReadOnly Property ExcludedGroupsFilter() As String Implements ICleaner.ExcludedGroupsFilter
        Get
            'TODO: make sure this loop works the same as the hard coded array list
            Dim sl As Collections.Specialized.StringCollection = _
                My.Settings.UserManagementAttributeCleanupExcludedGroups

            Dim filter As String = ""

            Dim s As String
            For Each s In sl
                filter &= "(!memberof=" & "CN=" & s & "," & My.Settings.LDAPOUDN & ")"
            Next

            Return filter
        End Get
    End Property

    Public ReadOnly Property StaleLogonDate() As Date Implements ICleaner.StaleLogonDate
        Get
            Return DateAdd(DateInterval.Day, (My.Settings.UserManagementStaleLogonDays * -1), System.DateTime.Now)
        End Get
    End Property

    Public ReadOnly Property StaleModifiedDate() As Date Implements ICleaner.StaleModifiedDate
        Get
            Return DateAdd(DateInterval.Day, (My.Settings.UserManagementStaleModifiedDays * -1), System.DateTime.Now)
        End Get
    End Property

    Public Function getDeletionCandidate() As DataTable Implements ICleaner.getDeletionCandidate

        Dim myAD As ADHelper = ADHelper.GetInstance

        Dim groupFilter As String
        If My.Settings.UserManagementTargetGroupCN.Length > 0 Then
            groupFilter = "CN=" & My.Settings.UserManagementTargetGroupCN & "," & My.Settings.LDAPOUDN
        Else
            groupFilter = ""
        End If

        Dim filter As String = "(userAccountControl:1.2.840.113556.1.4.803:=2)"
        filter &= Me.ExcludedGroupsFilter
        Dim properties As String = "cn,sn,givenname,SAMAccountName,mail,initials,lastLogonTimestamp,modifyTimeStamp"

        Dim dt As DataTable
        dt = myAD.getAccounts(myAD.LDAPRoot, "user", groupFilter, properties, filter)

        myAD.AddTranslatedTimeStamp(dt, "lastlogontimestamp", "LastLogonDate")
        myAD.AddTranslatedTimeString(dt, "modifytimestamp", "LastModifiedDate")

        'filter the dataset for dates
        Dim rowFilter As String
        'lastlogon date less than the stale date
        rowFilter = "ISNULL(LastLogonDate,'01/01/1900') < '" & Me.StaleLogonDate & "'"
        rowFilter &= " AND "
        'modified date less than the stale date
        rowFilter &= "ISNULL(LastModifiedDate,'01/01/1900') < '" & Me.StaleModifiedDate & "'"

        Dim dv As DataView = New DataView(dt)
        dv.RowFilter = rowFilter

        Return dv.ToTable

    End Function

    Public Function getDisableCandidates() As DataTable Implements ICleaner.getDisableCandidates

        Dim myAD As ADHelper = ADHelper.GetInstance

        Dim groupFilter As String
        If My.Settings.UserManagementTargetGroupCN.Length > 0 Then
            groupFilter = "CN=" & My.Settings.UserManagementTargetGroupCN & "," & My.Settings.LDAPOUDN
        Else
            groupFilter = ""
        End If

        'build the filter
        Dim filter As String
        'accounts not already disabled
        filter = "(!userAccountControl:1.2.840.113556.1.4.803:=2)"
        filter &= Me.ExcludedGroupsFilter

        Dim properties As String = "cn,sn,givenname,SAMAccountName,mail,initials,lastLogonTimestamp,modifyTimeStamp"

        Dim groupDN As String = "CN=" & My.Settings.UserManagementPendingDisableGroupCN & "," & My.Settings.LDAPOUDN

        Dim dt As DataTable
        dt = myAD.getAccounts(myAD.LDAPRoot, "user", groupDN, properties, filter)

        myAD.AddTranslatedTimeStamp(dt, "lastlogontimestamp", "LastLogonDate")
        myAD.AddTranslatedTimeString(dt, "modifytimestamp", "LastModifiedDate")

        'filter the dataset for dates
        Dim rowFilter As String
        'lastlogon date less than the stale date
        rowFilter = "ISNULL(LastLogonDate,'01/01/1900') < '" & Me.StaleLogonDate & "'"
        rowFilter &= " AND "
        'modified date less than the stale date
        rowFilter &= "ISNULL(LastModifiedDate,'01/01/1900') < '" & Me.StaleModifiedDate & "'"

        Dim dv As DataView = New DataView(dt)
        dv.RowFilter = rowFilter

        Return dv.ToTable

    End Function

    Public Function getStaleAccounts() As DataTable Implements ICleaner.getStaleItems

        Dim myAD As ADHelper = ADHelper.GetInstance

        Dim groupFilter As String
        If My.Settings.UserManagementTargetGroupCN.Length > 0 Then
            groupFilter = "CN=" & My.Settings.UserManagementTargetGroupCN & "," & My.Settings.LDAPOUDN
        Else
            groupFilter = ""
        End If

        'build the filter
        Dim filter As String
        'accounts not already disabled
        filter = "(!userAccountControl:1.2.840.113556.1.4.803:=2)"
        'not already a member of the stale accounts group
        filter &= "(!memberof=" & "CN=" & My.Settings.UserManagementPendingDisableGroupCN & "," & My.Settings.LDAPOUDN & ")"
        filter &= Me.ExcludedGroupsFilter

        Dim properties As String = "cn,sn,givenname,SAMAccountName,mail,initials,lastLogonTimestamp,modifyTimeStamp"

        'get the target accounts
        Dim dt As DataTable = myAD.getAccounts(myAD.LDAPRoot, "user", groupFilter, properties, filter)
        myAD.AddTranslatedTimeStamp(dt, "lastlogontimestamp", "LastLogonDate")
        myAD.AddTranslatedTimeString(dt, "modifytimestamp", "LastModifiedDate")

        'filter the dataset for dates
        Dim rowFilter As String
        'lastlogon date less than the stale date
        rowFilter = "ISNULL(LastLogonDate,'01/01/1900') < '" & Me.StaleLogonDate & "'"
        rowFilter &= " AND "
        'modified date less than the stale date
        rowFilter &= "ISNULL(LastModifiedDate,'01/01/1900') < '" & Me.StaleModifiedDate & "'"

        Dim dv As DataView = New DataView(dt)
        dv.RowFilter = rowFilter

        Return dv.ToTable

    End Function

    Public Sub MarkAsPendingDisable(ByVal UserCN As String, Optional ByVal LastLogonDate As Date = Nothing, _
        Optional ByVal LastModifiedDate As Date = Nothing) Implements ICleaner.MarkAsPendingDisable

        Dim myAD As ADHelper = ADHelper.GetInstance

        If Not myAD.IsMemberOfGroup(My.Settings.UserManagementPendingDisableGroupCN, UserCN) Then
            myAD.AddUserToGroup(My.Settings.UserManagementPendingDisableGroupCN, UserCN)

            Dim comment As String = DateTime.Today.ToString & " - identified as a stale login, marked as pending disable"
            If Not LastLogonDate = Nothing Then
                comment &= vbCrLf & "Last logon date of " & LastLogonDate.ToString
            End If
            comment &= vbCrLf & "Last modified " & LastModifiedDate.ToString

            myAD.AppendComment(UserCN, comment)
        End If

    End Sub

    Public Sub DisableAccount(ByVal UserCN As String, Optional ByVal LastLogonDate As Date = Nothing, _
        Optional ByVal LastModifiedDate As Date = Nothing) Implements ICleaner.DisableItem

        Dim myAD As ADHelper = ADHelper.GetInstance
        myAD.DisableAccount(UserCN)

        Dim comment As String = DateTime.Today.ToString & " - disabled user account, previously identified as a stale login and marked as pending disable"
        If Not LastLogonDate = Nothing Then
            comment &= vbCrLf & "Last logon date of " & LastLogonDate.ToString
        Else
            comment &= vbCrLf & "Last logon date not present"
        End If
        comment &= vbCrLf & "Last modified " & LastModifiedDate.ToString

        myAD.AppendComment(UserCN, comment)

    End Sub

End Class
